use std::{mem, ops::Deref, task::Poll};

use actix_web::{
    body::{BodySize, BoxBody, MessageBody},
    web::Bytes,
    HttpResponse, Responder,
};

use crate::error::AppErr;

use super::cfg::{HTTP_RESP_HEAD, HTTP_RESP_OK};

pub mod cbor;
pub mod device_session;
pub mod download;
pub mod event;
pub mod user_session;
pub mod session;

pub struct RawBody(pub Box<[u8]>);

impl Deref for RawBody {
    type Target = Box<[u8]>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl MessageBody for RawBody {
    type Error = AppErr;

    fn size(&self) -> BodySize {
        BodySize::Sized(self.len() as u64)
    }

    fn try_into_bytes(self) -> Result<Bytes, Self>
    where
        Self: Sized,
    {
        Ok(Bytes::from(self.0))
    }

    fn poll_next(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
    ) -> Poll<Option<Result<Bytes, Self::Error>>> {
        let this = self.get_mut();
        if this.is_empty() {
            return Poll::Ready(None);
        }
        let buf = mem::take(&mut this.0);
        Poll::Ready(Some(Ok(Bytes::from(buf))))
    }
}

pub struct Void;

impl Responder for Void {
    type Body = BoxBody;

    fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse {
        HttpResponse::Ok()
            .insert_header((HTTP_RESP_HEAD, HTTP_RESP_OK))
            .finish()
    }
}
